﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml;

namespace TimeSheetNote
{
    public partial class Form1 : Form
    {
        /* ИЗМЕНЕНИЕ
         * Контролы оставить только для отображения.
         * По типу, как деляю списки с тагом, в котором хранится сам объект
         * По событиям изменения контрола менять и данные объекта в таге
         * ТАК ПРОЗРАЧНЕЕ И ПРОЩЕ
         */

        List<TaskCntrl> tl = new List<TaskCntrl>();

        DateTime ActDay = DateTime.Today;

        /// <summary>Выборан не текущий день</summary>
        bool bSelectDifferentDate = false;

        public Form1()
        {
            InitializeComponent();

            Gl.dPathSave = Application.StartupPath;
            if (!Directory.Exists(Gl.dPathSave)) Directory.CreateDirectory(Gl.dPathSave);

            /*Gl.ConvertOldSaves();
            Close();*/

            Gl.dPathBackups = Application.StartupPath + "\\Backups";
            if (!Directory.Exists(Gl.dPathBackups)) Directory.CreateDirectory(Gl.dPathBackups);

            Gl.LoadDB();

            bChangeDate = true;
            CldActDay.Value = ActDay;
            bChangeDate = false;

            LoadActDay();

        }

        #region *** события Task ************************************************************************

        bool bModifyText = false;
        void Task_UserModifyText(object sender, EventArgs e)
        {
            dtNextSave = DateTime.Now.AddSeconds(2);
            bModifyText = true;
        }

        void Task_UserModifyTime(object sender, EventArgs e)
        {
            dtNextSave = DateTime.Now.AddSeconds(2);
        }

        void Task_StartStop(object sender, EventArgs e)
        {
            // останавливаем остальные
            int ind = ((TaskCntrl)sender).Ind;
            for (int i = 0; i < tl.Count; i++)
                if (i != ind && tl[i].IsRun) tl[i].Stop();
        }

        void Task_Delete(object sender, EventArgs e)
        {
            int ind = ((TaskCntrl)sender).Ind;
            if (tl[ind].TxbText != "" || tl[ind].Time > 0)
                if (MessageBox.Show("Действительно удалить задачу?", "Удаление задачи", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No) return;

            tl[ind].Tsk.Days.Remove(ActDay);
            Gl.DeleteEmptyTasks();

            tl[ind].Dispose();
            tl.RemoveAt(ind);
            ReposTasks();
            RefillPnlLast();

            dtNextSave = DateTime.Now;
        }

        void Task_OpenClose(object sender, EventArgs e)
        {
            dtNextSave = DateTime.Now;
        }

        #endregion *** события Task ************************************************************************

        void SaveDB()
        {
            SetStat("Сохранение", 0.5);
            Gl.SaveDB();
        }

        /// <summary>Заполнение списка задач для текущего дня</summary>
        void LoadActDay()
        {
            ClearTaskList();
            dtEndWorkDay = ActDay.AddHours(15).AddMinutes(30);

            List<TaskEl> tsl = Gl.GetDayTasks(ActDay);
            foreach (TaskEl tsEl in tsl) AddExistTaskInDay(tsEl);

            RefillPnlLast();
        }

        void ClearTaskList()
        {
            foreach (TaskCntrl tsk in tl)
                tsk.Dispose();
            tl.Clear();
        }

        void ReposTasks()
        {
            for (int i = 0; i < tl.Count; i++)
            {
                tl[i].Ind = i;
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            AddNewTaskInDay("");
            dtNextSave = DateTime.Now;
        }

        void AddNewTaskInDay(string text)
        {
            TaskEl tsk = Gl.AddTaskInDB(text);
            tsk.Days.Add(ActDay, 0);
            TaskCntrl tskCntrl = new TaskCntrl(pnlItems, tl.Count, tsk, ActDay);

            tskCntrl.UserModifyText += new EventHandler(Task_UserModifyText);
            tskCntrl.UserModifyTime += new EventHandler(Task_UserModifyTime);
            tskCntrl.UserStartStop += new EventHandler(Task_StartStop);
            tskCntrl.DeleteClick += new EventHandler(Task_Delete);
            tskCntrl.CloseClick += new EventHandler(Task_OpenClose);
            tl.Add(tskCntrl);
            pnlItems.Height = tskCntrl.Bottom + 5;
        }

        void AddExistTaskInDay(TaskEl tsk)
        {
            int time = 0;
            if (tsk.Days.ContainsKey(ActDay)) time = tsk.Days[ActDay];
            else tsk.Days.Add(ActDay, 0);

            TaskCntrl tskCntrl = new TaskCntrl(pnlItems, tl.Count, tsk, ActDay);
            tskCntrl.UserModifyText += new EventHandler(Task_UserModifyText);
            tskCntrl.UserModifyTime += new EventHandler(Task_UserModifyTime);
            tskCntrl.UserStartStop += new EventHandler(Task_StartStop);
            tskCntrl.DeleteClick += new EventHandler(Task_Delete);
            tskCntrl.CloseClick += new EventHandler(Task_OpenClose);
            tl.Add(tskCntrl);
            pnlItems.Height = tskCntrl.Bottom + 5;
        }

        void RunQuickTask(TaskEl tsk)
        {
            int ind = -1;
            for (int i = 0; i < tl.Count; i++) if (tl[i].Tsk.ID == tsk.ID) { ind = i; break; }
            if (ind == -1)
            {
                // проверка существования в БД (на всякий)
                if (Gl.GetTaskByID(tsk.ID) == null) { MessageBox.Show("ОШИБКА. Задачи нет в БД"); return; }

                AddExistTaskInDay(tsk);
                ind = tl.Count - 1;
                SaveDB();
            }

            if (!tsk.IsClose)
            {
                StopTask();
                tl[ind].Start(); // запуск
            }

            dtNextSave = DateTime.Now;
        }

        void StopTask()
        {
            for (int i = 0; i < tl.Count; i++) if (tl[i].IsRun) tl[i].Stop();
        }

        DateTime dtNextSave = DateTime.Now.AddSeconds(10);
        DateTime dtHideStat = DateTime.MaxValue; // время скрытия статуса
        DateTime dtEndWorkDay = DateTime.MaxValue;

        DateTime dtNextBackup = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, 0, 0);

        private void tmr_Tick(object sender, EventArgs e)
        {
            tmr.Stop();

            // Backup
            if (dtNextBackup <= DateTime.Now)
            {
                Gl.SaveDBBackup();
                dtNextBackup = dtNextBackup.AddHours(1);
            }

            // смена суток
            if (ActDay != DateTime.Today && !bSelectDifferentDate)
            {
                ChangeDay(DateTime.Today);
            }

            int SumTime = 0;
            foreach (TaskCntrl tsk in tl) { tsk.Tick(); SumTime += (tsk.Time / 60) * 60; }

            // сохранение
            if (dtNextSave <= DateTime.Now)
            {
                dtNextSave = DateTime.Now.AddSeconds(10);
                SaveDB();
                // если был изменен текст, перезаполняем список последних не закрытых
                if (bModifyText) { RefillPnlLast(); bModifyText = false; }
            }

            // скрытие статуса
            if (dtHideStat <= DateTime.Now) { lblStat.Text = ""; dtHideStat = DateTime.MaxValue; }

            // общее время
            lblAllTime.Text = DateTime.Today.AddSeconds(SumTime).ToString("HH:mm");
            lblWorkTime.Text = GetWorkDayTime(DateTime.Today.AddHours(8));

            // окончание рабочего дня
            if (dtEndWorkDay <= DateTime.Now)
            {
                // запоминаем, запушеную задачу и останавливаем все
                int indRun = -1;
                for (int i = 0; i < tl.Count; i++)
                {
                    if (tl[i].IsRun) { indRun = i; tl[i].Stop(); break; }
                }

                if (indRun != -1)
                {
                    if (MessageBox.Show("Рабочий день закончился. Все задачи остановлены.\r\nПродолжить выполнение задач?", "Окончание рабочего дня", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        tl[indRun].Start();
                        dtEndWorkDay = DateTime.MaxValue;
                    }
                }
                else dtEndWorkDay = DateTime.MaxValue;
            }

            tmr.Start();
        }

        bool bChangeDate = false;
        void ChangeDay(DateTime NewDay)
        {
            bChangeDate = true;
            StopTask();
            SaveDB();

            CldActDay.Value = NewDay;
            ActDay = NewDay;
            LoadActDay();
            bSelectDifferentDate = DateTime.Today != NewDay;
            bChangeDate = false;
        }

        string GetWorkDayTime(DateTime StartTime)
        {
            TimeSpan ts = (DateTime.Now - StartTime);
            if (chbxLunch.Checked) ts = ts.Add(new TimeSpan(0, -30, 0));
            if (ts.TotalSeconds < 0) return "-" + ((int)Math.Abs(ts.Hours)).ToString("00") + ":" + ((int)Math.Abs(ts.Minutes)).ToString("00");
            else return ts.Hours.ToString("00") + ":" + ts.Minutes.ToString("00");
        }

        /// <summary> Показ статуса </summary>
        /// <param name="TimeShowStat">Время показа статуса (сек)</param>
        void SetStat(string text, double TimeShowStat)
        {
            dtHideStat = TimeShowStat == 0 ? DateTime.MaxValue : DateTime.Now.AddSeconds(TimeShowStat);
            lblStat.Text = text;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveDB();
        }

        private void btnHistory_Click(object sender, EventArgs e)
        {
            FormHistory frmHist = new FormHistory();
            frmHist.ShowDialog();
            frmHist.Dispose();
        }

        private void btnAddTaskRun_Click(object sender, EventArgs e)
        {
            TaskEl el = Gl.GetTaskByID(-3);
            RunQuickTask(el == null ? Gl.Presets.Find(t => t.ID == -3) : el);
        }

        void btnPresetTask_Click(object sender, EventArgs e)
        {
            RunQuickTask((TaskEl)((Button)sender).Tag);
        }

        void RefillPnlLast()
        {
            //foreach (Control cntrl in pnlLast.Controls) cntrl.Dispose();
            pnlLast.Controls.Clear();

            // выборка не закрытых
            List<TaskEl> lastEl = Gl.GetNotCloseTasks();

            for (int i = 0; i < lastEl.Count; i++)
            {
                // проверка не пресет ли
                if (lastEl[i].ID < 0) { lastEl.RemoveAt(i); i--; continue; }

                // проверка нет ли в уже в существующих за этот день
                bool bExist = false;
                foreach (TaskCntrl tsk in tl) if (tsk.Tsk.ID == lastEl[i].ID) { bExist = true; break; }
                if (bExist) { lastEl.RemoveAt(i); i--; continue; }

            }

            // размещение не закрытых в виде списка кнопок
            for (int i = 0; i < lastEl.Count; i++)
            {
                Button btn = new Button();
                btn.Location = new Point(5, 5 + i * 35);
                btn.Size = new Size(pnlLast.ClientSize.Width - 10, 36);
                btn.Text = lastEl[i].ID.ToString() + ") " + lastEl[i].Text.Replace('\r', ' ').Replace('\n', ' ');
                btn.Tag = lastEl[i];
                btn.Click += new EventHandler(btnLastTask_Click);

                pnlLast.SuspendLayout();
                pnlLast.Controls.Add(btn);
                btn.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
                pnlLast.ResumeLayout();
            }

        }

        void btnLastTask_Click(object sender, EventArgs e)
        {
            RunQuickTask((TaskEl)((Button)sender).Tag);
            RefillPnlLast();
        }

        private void toolStripDropDownButton1_DropDownOpening(object sender, EventArgs e)
        {
            List<TaskEl> tlClose = Gl.GetCloseTasks();
            TaskEl.CmprMode = TaskEl.CompareMode.ID;
            tlClose.Sort();

            tBtnCloseTask.DropDownItems.Clear();
            for (int i = tlClose.Count - 1; i >= 0; i--)
            {

                // проверка не пресет ли
                if (tlClose[i].ID < 0) { continue; }

                // проверка нет ли в уже в существующих за этот день
                bool bExist = false;
                foreach (TaskCntrl tsk in tl) if (tsk.Tsk.ID == tlClose[i].ID) { bExist = true; break; }
                if (bExist) { continue; }

                ToolStripMenuItem itm = new ToolStripMenuItem();
                itm.Size = new System.Drawing.Size(300, 22);
                itm.Text = tlClose[i].ID.ToString() + ") " + tlClose[i].Text.Replace('\r', ' ').Replace('\n', ' ');
                itm.Tag = tlClose[i];
                itm.Click += new EventHandler(btnLastCloseTask_Click);
                tBtnCloseTask.DropDownItems.Add(itm);

                if ((tlClose.Count - i) > 100) break;
            }

        }

        void btnLastCloseTask_Click(object sender, EventArgs e)
        {
            RunQuickTask((TaskEl)((ToolStripMenuItem)sender).Tag);
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            /*FormAllTasks frm = new FormAllTasks();
            frm.ShowDialog1();
            frm.Dispose();
            SaveDB();
            LoadActDay();
            Close();*/
        }

        private void btnAllTasks_Click(object sender, EventArgs e)
        {
            FormAllTasks frm = new FormAllTasks();
            frm.ShowDialog1();
            frm.Dispose();
            SaveDB();
            LoadActDay();
        }

        private void CldActDay_ValueChanged(object sender, EventArgs e)
        {
            if (bChangeDate) return;
            ChangeDay(CldActDay.Value.Date);
        }

    }
}
